package gemini.pollux.ui.client.mvp.gin;

import gemini.pollux.ui.client.mvp.PlaceRequestManager;
import gemini.pollux.ui.client.mvp.container.PolluxWidgetContainerPresenter;
import gemini.pollux.ui.client.mvp.single.PolluxWidgetPresenter;
import gemini.pollux.ui.client.page.RootPresenter;
import gemini.pollux.ui.client.page.RootView;
import gemini.pollux.ui.client.page.content.marketingplan.level.LevelPresenter;
import gemini.pollux.ui.client.page.content.marketingplan.level.LevelView;
import gemini.pollux.ui.client.page.content.marketingplan.level.edit.LevelEditPresenter;
import gemini.pollux.ui.client.page.content.marketingplan.level.edit.LevelEditView;
import gemini.pollux.ui.client.page.content.marketingplan.level.list.LevelListPresenter;
import gemini.pollux.ui.client.page.content.marketingplan.level.list.LevelListView;
import gemini.pollux.ui.client.page.content.product.product.ProductPresenter;
import gemini.pollux.ui.client.page.content.product.product.ProductView;
import gemini.pollux.ui.client.page.content.product.product.edit.ProductEditPresenter;
import gemini.pollux.ui.client.page.content.product.product.edit.ProductEditView;
import gemini.pollux.ui.client.page.content.product.product.list.ProductListPresenter;
import gemini.pollux.ui.client.page.content.product.product.list.ProductListView;
import gemini.pollux.ui.client.page.content.product.producttype.ProductTypePresenter;
import gemini.pollux.ui.client.page.content.product.producttype.ProductTypeView;
import gemini.pollux.ui.client.page.content.product.producttype.edit.ProductTypeEditPresenter;
import gemini.pollux.ui.client.page.content.product.producttype.edit.ProductTypeEditView;
import gemini.pollux.ui.client.page.content.product.producttype.list.ProductTypeListPresenter;
import gemini.pollux.ui.client.page.content.product.producttype.list.ProductTypeListView;
import ch.elca.gwt.mvp.client.DefaultEventBus;
import ch.elca.gwt.mvp.client.Display;
import ch.elca.gwt.mvp.client.EventBus;
import ch.elca.gwt.mvp.client.place.PlaceManager;

import com.google.gwt.inject.client.AbstractGinModule;
import com.google.inject.Singleton;

public class PolluxModule extends AbstractGinModule {

    @Override
    protected void configure() {
    	bind(EventBus.class).to(DefaultEventBus.class).in(Singleton.class);
        bind(PlaceManager.class).in(Singleton.class);
        bind(PlaceRequestManager.class).in(Singleton.class);

        bindPresenters();
    }

    private void bindPresenters() {
    	bindSingleton(RootPresenter.class, RootPresenter.Display.class, RootView.class);

    	bindSingletonContainer(LevelPresenter.class, LevelPresenter.Display.class, LevelView.class);
    	bindSingleton(LevelListPresenter.class, LevelListPresenter.Display.class, LevelListView.class);
    	bindSingleton(LevelEditPresenter.class, LevelEditPresenter.Display.class, LevelEditView.class);
    	
    	bindSingletonContainer(ProductTypePresenter.class, ProductTypePresenter.Display.class, ProductTypeView.class);
    	bindSingleton(ProductTypeListPresenter.class, ProductTypeListPresenter.Display.class, ProductTypeListView.class);
    	bindSingleton(ProductTypeEditPresenter.class, ProductTypeEditPresenter.Display.class, ProductTypeEditView.class);
    	
    	bindSingletonContainer(ProductPresenter.class, ProductPresenter.Display.class, ProductView.class);
    	bindSingleton(ProductListPresenter.class, ProductListPresenter.Display.class, ProductListView.class);
    	bindSingleton(ProductEditPresenter.class, ProductEditPresenter.Display.class, ProductEditView.class);
    }

    /**
     * Lets GIN know that it must return the same presenter instance everytime
     * (that means the presenter must be stateless). After that bind the display
     * interface (which is a contract between the presenter and its view) with
     * the view.
     */
    private <D extends Display> void bindSingleton(
            final Class<? extends PolluxWidgetPresenter<? extends D>> presenterClass,
            final Class<D> displayClass, final Class<? extends D> viewClass) {
        bind(presenterClass).in(Singleton.class);
        bind(displayClass).to(viewClass);
    }
    
    private <D extends Display> void bindSingletonContainer(
            final Class<? extends PolluxWidgetContainerPresenter<? extends D>> presenterClass,
            final Class<D> displayClass, final Class<? extends D> viewClass) {
        bind(presenterClass).in(Singleton.class);
        bind(displayClass).to(viewClass);
    }

    /**
     * Works the same as method <code>bindSingleton</code> except GIN will
     * return a new instance of presenter everytime.
     */
    @SuppressWarnings("unused")
	private <D extends Display> void bindNoneSingleton(
            final Class<? extends PolluxWidgetPresenter<? extends D>> presenterClass, final Class<D> displayClass,
            final Class<? extends D> viewClass) {
        bind(presenterClass);
        bind(displayClass).to(viewClass);
    }
}
